# This file is included in top level before the defining of any targets
# Contents here will setup the flags and steps common to all targets

if(NOT SET_UP_PRE_TARGET_PROPERTIES_CONFIGURATION_DONE)
    set(SET_UP_PRE_TARGET_PROPERTIES_CONFIGURATION_DONE TRUE)

    # No reason to set CMAKE_CONFIGURATION_TYPES if it's not a multiconfig generator
    # Also no reason mess with CMAKE_BUILD_TYPE if it's a multiconfig generator.
    get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
    if(isMultiConfig AND MSVC )
        set(CMAKE_CONFIGURATION_TYPES "DxDebug;DxRelease;DxDebugExperimental;DxReleaseExperimental;VkRelease;VkDebug" CACHE STRING "" FORCE)
    elseif(isMultiConfig AND XCODE)
        set(CMAKE_CONFIGURATION_TYPES "VkRelease;VkDebug" CACHE STRING "" FORCE)
    else()
        if(NOT CMAKE_BUILD_TYPE)
            message("Defaulting to release build.")
            set(CMAKE_BUILD_TYPE DxRelease CACHE STRING "" FORCE)
        endif()
        set_property(CACHE CMAKE_BUILD_TYPE PROPERTY HELPSTRING "Choose the type of build")
        # set the valid options for cmake-gui drop-down list
        set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "DxDebug;DxRelease;VkRelease;VkDebug")
    endif()

    # skip generating of unnecessary files
    set(CMAKE_SKIP_INSTALL_RULES True)

    # Set up all the configurations
    #   Now set up the DxRelease configuration
    set(CMAKE_EXE_LINKER_FLAGS_DXRELEASE ${CMAKE_EXE_LINKER_FLAGS_RELEASE})
    set(CMAKE_CXX_FLAGS_DXRELEASE ${CMAKE_CXX_FLAGS_RELEASE})
    set(CMAKE_C_FLAGS_DXRELEASE ${CMAKE_C_FLAGS_RELEASE})

    #   Now set up the DxDebug configuration
    set(CMAKE_EXE_LINKER_FLAGS_DXDEBUG ${CMAKE_EXE_LINKER_FLAGS_DEBUG})
    set(CMAKE_CXX_FLAGS_DXDEBUG ${CMAKE_CXX_FLAGS_DEBUG})
    set(CMAKE_C_FLAGS_DXDEBUG ${CMAKE_C_FLAGS_DEBUG})

    #   Now set up the DxReleaseExperimental configuration
    set(CMAKE_EXE_LINKER_FLAGS_DXRELEASEEXPERIMENTAL ${CMAKE_EXE_LINKER_FLAGS_RELEASE})
    set(CMAKE_CXX_FLAGS_DXRELEASEEXPERIMENTAL ${CMAKE_CXX_FLAGS_RELEASE})
    set(CMAKE_C_FLAGS_DXRELEASEEXPERIMENTAL ${CMAKE_C_FLAGS_RELEASE})

    #   Now set up the DxDebugExperimental configuration
    set(CMAKE_EXE_LINKER_FLAGS_DXDEBUGEXPERIMENTAL ${CMAKE_EXE_LINKER_FLAGS_DEBUG})
    set(CMAKE_CXX_FLAGS_DXDEBUGEXPERIMENTAL ${CMAKE_CXX_FLAGS_DEBUG})
    set(CMAKE_C_FLAGS_DXDEBUGEXPERIMENTAL ${CMAKE_C_FLAGS_DEBUG})

    #   Now set up the VkRelease configuration
    set(CMAKE_EXE_LINKER_FLAGS_VKRELEASE ${CMAKE_EXE_LINKER_FLAGS_RELEASE})
    set(CMAKE_CXX_FLAGS_VKRELEASE ${CMAKE_CXX_FLAGS_RELEASE})
    set(CMAKE_C_FLAGS_DXDEBUG ${CMAKE_C_FLAGS_DEBUG})

    #   Now set up the VkDebug configuration
    set(CMAKE_EXE_LINKER_FLAGS_VKDEBUG  ${CMAKE_EXE_LINKER_FLAGS_DEBUG})
    set(CMAKE_CXX_FLAGS_VKDEBUG ${CMAKE_CXX_FLAGS_DEBUG})
    set(CMAKE_C_FLAGS_DXDEBUG ${CMAKE_C_FLAGS_DEBUG})

    # Set up compile definitions
    add_compile_definitions(
        $<$<CONFIG:DxDebug>:DX_MICRO=1>
        $<$<CONFIG:DxRelease>:DX_MICRO=1>
        $<$<CONFIG:DxDebugExperimental>:DX_MICRO=1>
        $<$<CONFIG:DxReleaseExperimental>:DX_MICRO=1>
        $<$<CONFIG:DxDebugExperimental>:EXPERIMENTAL_MODE=1>
        $<$<CONFIG:DxReleaseExperimental>:EXPERIMENTAL_MODE=1>
        $<$<CONFIG:VkDebug>:VULKAN_MICRO=1>
        $<$<CONFIG:VkRelease>:VULKAN_MICRO=1>
    )

    # To see what commands are being used for compilation
    set(CMAKE_EXPORT_COMPILE_COMMANDS 1)

    # Required cpp standard
    set(CMAKE_CXX_STANDARD 20)

    # Use solution directories to group projects correctly
    set_property(GLOBAL PROPERTY USE_FOLDERS ON)

    # Some projects include headers relative to root directory hence making it available
    include_directories( ${PROJECT_SOURCE_DIR} )

    # Set important variables for Vulkan configs
    set(VULKAN_SDK_PATH $ENV{VULKAN_SDK})
    set(MOLTEN_VK_ICD $ENV{MOLTEN_VK_ICD})
    set(VK_LAYER_PATH $ENV{VK_LAYER_PATH})

    # Set important variables for WINDOWS configs
    if(WIN32)
        set(PLATFORM_TYPE Win64)
        set(CMAKE_SUPPRESS_REGENERATION OFF)
        set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:DxDebug,DxDebugExperimental,VkDebug>:Debug>DLL")
        add_definitions(-D_CRT_SECURE_NO_WARNINGS)
    elseif(APPLE)
        set(PLATFORM_TYPE MacosArm64)
    else()
        set(PLATFORM_TYPE Linux64)
    endif()

    # Define common post build steps

    # Helper functions to copy files required for running microbenchmarks
    ## Unconditional copy files
    function(copy_dll_file src_dll_rel dest_dir target_dependent_dll_files)
        string(REPLACE "/" "_" src_dll_path ${src_dll_rel})
        set(DUMMY_NAME "dummy_${src_dll_path}")
        set(src_dll ${CMAKE_SOURCE_DIR}/../libs/${src_dll_rel})
        get_filename_component(dll_name ${src_dll} NAME)
        if (dest_dir STREQUAL "")
            set(dest_dir_path "")
        else()
            set(dest_dir_path "${dest_dir}/")
        endif()
        set(dest_dll ${CMAKE_SOURCE_DIR}/../Bin/$<CONFIG>/${dest_dir_path}${dll_name})
        add_custom_command(OUTPUT ${dest_dll}
            COMMAND ${CMAKE_COMMAND} -E copy_if_different "${src_dll}" "${dest_dll}"
            COMMAND ${CMAKE_COMMAND} -E echo "Copy ${src_dll} to ${dest_dll}"
            DEPENDS ${src_dll}
            )
        list(APPEND target_dependent_dll_files ${dest_dll})
        set(target_dependent_dll_files "${target_dependent_dll_files}" PARENT_SCOPE)
    endfunction()

    ## Conditional copy files - only applicable in target is given Config
    function(copy_dll_file_if_config src_dll_rel dest_dir config_list target_dependent_dll_files)
        string(REPLACE "/" "_" src_dll_path ${src_dll_rel})
        set(DUMMY_NAME "${src_dll_path}_dummy")
        set(src_dll ${CMAKE_SOURCE_DIR}/../libs/${src_dll_rel})
        get_filename_component(dll_name ${src_dll} NAME)
        if (dest_dir STREQUAL "")
            set(dest_dir_path "")
        else()
            set(dest_dir_path "${dest_dir}/")
        endif()
        set(dest_dll ${CMAKE_SOURCE_DIR}/../Bin/$<CONFIG>/${dest_dir_path}${dll_name})
        foreach(config_name in ${config_list})
            add_custom_command(OUTPUT $<IF:$<CONFIG:${config_name}>,${dest_dll},${DUMMY_NAME}>
                COMMAND ${CMAKE_COMMAND} -E $<IF:$<CONFIG:${config_name}>,copy_if_different,true> "${src_dll}" ${dest_dll}
                COMMAND ${CMAKE_COMMAND} -E $<IF:$<CONFIG:${config_name}>,echo,true> "Copy ${src_dll} to ${${dest_dll}}"
                COMMAND ${CMAKE_COMMAND} -E $<IF:$<CONFIG:${config_name}>,true,touch> ${DUMMY_NAME}
                DEPENDS $<$<CONFIG:${config_name}>:${src_dll}>
                )
            list(APPEND target_dependent_dll_files $<$<CONFIG:${config_name}>:${dest_dll}>)
        endforeach()
        set(target_dependent_dll_files "${target_dependent_dll_files}" PARENT_SCOPE)
    endfunction()

    function (BuildDLLs)
        set(target_dependent_dll_files "")

        # Handle dlls for all targets
        copy_dll_file("NVAPI/x64/nvapi64.dll" "" "${target_dependent_dll_files}")
        copy_dll_file("GPUZ/x64/GpuZ.dll" "" "${target_dependent_dll_files}")

        # Handle dlls for all DX12 builds
        set(DXConfigs "DxDebug;DxRelease;DxDebugExperimental;DxReleaseExperimental")
        copy_dll_file_if_config("WinPix/x64/WinPixEventRuntime.dll" "" "${DXConfigs}" "${target_dependent_dll_files}")
        copy_dll_file_if_config("GPA-AMD/x64/GPUPerfAPIDX12-x64.dll" "" "${DXConfigs}" "${target_dependent_dll_files}")

        # Handle dlls for stable DX12 builds
        set(DXStableConfigs "DxDebug;DxRelease")
        copy_dll_file_if_config("D3D12/x64/D3D12Core.dll" "D3D12" "${DXStableConfigs}" "${target_dependent_dll_files}")
        copy_dll_file_if_config("D3D12/x64/d3d12SDKLayers.dll" "D3D12" "${DXStableConfigs}" "${target_dependent_dll_files}")
        copy_dll_file_if_config("D3D12/x64/dxcompiler.dll" "" "${DXStableConfigs}" "${target_dependent_dll_files}")
        copy_dll_file_if_config("D3D12/x64/dxil.dll" "" "${DXStableConfigs}" "${target_dependent_dll_files}")

        # Handle dlls for experimental DX12 builds
        set(DXExperimentalConfigs "DxDebugExperimental;DxReleaseExperimental")
        copy_dll_file_if_config("D3D12P/x64/D3D12Core.dll" "D3D12" "${DXExperimentalConfigs}" "${target_dependent_dll_files}")
        copy_dll_file_if_config("D3D12P/x64/d3d12SDKLayers.dll" "D3D12" "${DXExperimentalConfigs}" "${target_dependent_dll_files}")
        copy_dll_file_if_config("D3D12P/x64/dxcompiler.dll" "" "${DXExperimentalConfigs}" "${target_dependent_dll_files}")

        # Handle dlls for all VK builds
        set(VKConfigs "VkDebug;VkRelease")
        copy_dll_file_if_config("GLFW/x64/glfw3.dll" "" "${VKConfigs}" "${target_dependent_dll_files}")

        add_custom_target(DllFiles
                            DEPENDS ${target_dependent_dll_files}
                            )
        set_target_properties(DllFiles PROPERTIES FOLDER "_CoreDependencies")
    endfunction()

    BuildDLLs()

endif()
